summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2009-08-20 20:29:56 +0200
committerBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2009-08-20 22:09:52 +0200
commitee2670460af760bf07c47950a8cca37bd6814f2b (patch)
treef55d6213005f4fe0deee90ea53e9c2e106c3ab7b
parent1ffed52434741aa31b1549a931f6b446b2aaabd0 (diff)
Fix the most obvious rendering bugs when applying an effect to QWidget.
-rw-r--r--src/gui/kernel/qwidget.cpp95
-rw-r--r--src/gui/kernel/qwidget_p.h8
-rw-r--r--src/gui/kernel/qwidget_qws.cpp8
-rw-r--r--src/gui/kernel/qwidget_win.cpp4
-rw-r--r--src/gui/kernel/qwidget_x11.cpp4
-rw-r--r--src/gui/painting/qbackingstore.cpp37
-rw-r--r--src/gui/painting/qbackingstore_p.h8
7 files changed, 118 insertions, 46 deletions
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index a314cf195..a9ef6aa93 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -1551,9 +1551,9 @@ bool QWidgetPrivate::isOverlapped(const QRect &rect) const
continue;
}
- if (qRectIntersects(sibling->data->crect, r)) {
+ if (qRectIntersects(sibling->d_func()->effectiveRectFor(sibling->data->crect), r)) {
const QWExtra *siblingExtra = sibling->d_func()->extra;
- if (siblingExtra && siblingExtra->hasMask
+ if (siblingExtra && siblingExtra->hasMask && !sibling->d_func()->graphicsEffect
&& !siblingExtra->mask.translated(sibling->data->crect.topLeft()).intersects(r)) {
continue;
}
@@ -1794,12 +1794,14 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt
break;
QWidgetPrivate *pd = w->parentWidget()->d_func();
const int myIndex = pd->children.indexOf(const_cast<QWidget *>(w));
+ const QRect widgetGeometry = w->d_func()->effectiveRectFor(w->data->crect);
for (int i = myIndex + 1; i < pd->children.size(); ++i) {
QWidget *sibling = qobject_cast<QWidget *>(pd->children.at(i));
if (!sibling || !sibling->isVisible() || sibling->isWindow())
continue;
- if (!qRectIntersects(sibling->data->crect, w->data->crect))
+ const QRect siblingGeometry = sibling->d_func()->effectiveRectFor(sibling->data->crect);
+ if (!qRectIntersects(siblingGeometry, widgetGeometry))
continue;
if (dirtyClipBoundingRect) {
@@ -1807,7 +1809,7 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt
dirtyClipBoundingRect = false;
}
- if (!qRectIntersects(sibling->data->crect, clipBoundingRect.translated(parentOffset)))
+ if (!qRectIntersects(siblingGeometry, clipBoundingRect.translated(parentOffset)))
continue;
if (dirtyParentClip) {
@@ -1819,7 +1821,8 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt
const QRect siblingClipRect(sibling->d_func()->clipRect());
QRegion siblingDirty(parentClip);
siblingDirty &= (siblingClipRect.translated(siblingPos));
- const bool hasMask = sibling->d_func()->extra && sibling->d_func()->extra->hasMask;
+ const bool hasMask = sibling->d_func()->extra && sibling->d_func()->extra->hasMask
+ && !sibling->d_func()->graphicsEffect;
if (hasMask)
siblingDirty &= sibling->d_func()->extra->mask.translated(siblingPos);
if (siblingDirty.isEmpty())
@@ -1830,7 +1833,7 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt
siblingDirty.translate(-parentOffset);
sourceRegion -= siblingDirty;
} else {
- sourceRegion -= sibling->data->crect.translated(-parentOffset);
+ sourceRegion -= siblingGeometry.translated(-parentOffset);
}
} else {
if (hasDirtySiblingsAbove)
@@ -1861,6 +1864,11 @@ void QWidgetPrivate::clipToEffectiveMask(QRegion &region) const
const QWidget *w = q;
QPoint offset;
+ if (graphicsEffect) {
+ w = q->parentWidget();
+ offset -= data.crect.topLeft();
+ }
+
while (w) {
const QWidgetPrivate *wd = w->d_func();
if (wd->extra && wd->extra->hasMask)
@@ -5046,7 +5054,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
sourced->context = &context;
if (!sharedPainter) {
QPaintEngine *paintEngine = pdev->paintEngine();
- paintEngine->d_func()->systemClip = clipRect().translated(offset);
+ paintEngine->d_func()->systemClip = rgn.translated(offset);
QPainter p(pdev);
p.translate(offset);
context.painter = &p;
@@ -5054,7 +5062,10 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
paintEngine->d_func()->systemClip = QRegion();
} else {
context.painter = sharedPainter;
+ sharedPainter->save();
+ sharedPainter->translate(offset);
graphicsEffect->draw(sharedPainter, source);
+ sharedPainter->restore();
}
sourced->context = 0;
return;
@@ -5195,7 +5206,7 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis
dirtyBoundingRect = false;
}
- if (qRectIntersects(boundingRect, x->data->crect)) {
+ if (qRectIntersects(boundingRect, x->d_func()->effectiveRectFor(x->data->crect))) {
#ifdef Q_BACKINGSTORE_SUBSURFACES
if (x->windowSurface() == currentSurface)
#endif
@@ -5213,7 +5224,7 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis
QWidgetPrivate *wd = w->d_func();
const QPoint widgetPos(w->data->crect.topLeft());
- const bool hasMask = wd->extra && wd->extra->hasMask;
+ const bool hasMask = wd->extra && wd->extra->hasMask && !wd->graphicsEffect;
if (index > 0) {
QRegion wr(rgn);
@@ -5228,7 +5239,7 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis
if (w->updatesEnabled() && (!w->d_func()->extra || !w->d_func()->extra->proxyWidget)) {
QRegion wRegion(rgn);
- wRegion &= w->data->crect;
+ wRegion &= wd->effectiveRectFor(w->data->crect);
wRegion.translate(-widgetPos);
if (hasMask)
wRegion &= wd->extra->mask;
@@ -5236,6 +5247,20 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis
}
}
+QRectF QWidgetEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const
+{
+ if (system != Qt::DeviceCoordinates)
+ return m_widget->rect();
+
+ if (!context) {
+ // Device coordinates without context not yet supported.
+ qWarning("QGraphicsEffectSource::boundingRect: Not yet implemented, lacking device context");
+ return QRectF();
+ }
+
+ return context->painter->worldTransform().mapRect(m_widget->rect());
+}
+
void QWidgetEffectSourcePrivate::draw(QPainter *painter)
{
if (!context || context->painter != painter) {
@@ -5243,24 +5268,64 @@ void QWidgetEffectSourcePrivate::draw(QPainter *painter)
return;
}
- qt_widget_private(m_widget)->drawWidget(context->pdev, context->rgn, context->offset, context->flags,
- context->sharedPainter, context->backingStore);
+ // The region saved in the context is neither clipped to the rect
+ // nor the mask, so we have to clip it here before calling drawWidget.
+ QRegion toBePainted = context->rgn;
+ toBePainted &= m_widget->rect();
+ QWidgetPrivate *wd = qt_widget_private(m_widget);
+ if (wd->extra && wd->extra->hasMask)
+ toBePainted &= wd->extra->mask;
+
+ wd->drawWidget(context->pdev, toBePainted, context->offset, context->flags,
+ context->sharedPainter, context->backingStore);
}
QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset) const
{
const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
+ if (!context && deviceCoordinates) {
+ // Device coordinates without context not yet supported.
+ qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context");
+ return QPixmap();
+ }
+
QPoint pixmapOffset;
+ QRectF sourceRect = m_widget->rect();
- QRect sourceRect(m_widget->rect());
if (deviceCoordinates) {
- pixmapOffset = m_widget->mapTo(m_widget->window(), QPoint());
- sourceRect.translate(pixmapOffset);
+ const QTransform &painterTransform = context->painter->worldTransform();
+ sourceRect = painterTransform.mapRect(sourceRect);
+ pixmapOffset = painterTransform.map(pixmapOffset);
}
QRect effectRect = m_widget->graphicsEffect()->boundingRectFor(sourceRect).toAlignedRect();
if (offset)
*offset = effectRect.topLeft();
+
+ if (deviceCoordinates) {
+ // Clip to device rect.
+ int left, top, right, bottom;
+ effectRect.getCoords(&left, &top, &right, &bottom);
+ if (left < 0) {
+ if (offset)
+ offset->rx() += -left;
+ effectRect.setX(0);
+ }
+ if (top < 0) {
+ if (offset)
+ offset->ry() += -top;
+ effectRect.setY(0);
+ }
+ // NB! We use +-1 for historical reasons (see QRect documentation).
+ QPaintDevice *device = context->painter->device();
+ const int deviceWidth = device->width();
+ const int deviceHeight = device->height();
+ if (right + 1 > deviceWidth)
+ effectRect.setRight(deviceWidth - 1);
+ if (bottom + 1 > deviceHeight)
+ effectRect.setBottom(deviceHeight -1);
+ }
+
pixmapOffset -= effectRect.topLeft();
QPixmap pixmap(effectRect.size());
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index acfb6c355..69fcbbc15 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -694,13 +694,7 @@ public:
inline QRect deviceRect() const
{ return m_widget->window()->rect(); }
- inline QRectF boundingRect(Qt::CoordinateSystem system) const
- {
- if (system == Qt::LogicalCoordinates)
- return m_widget->rect();
- return m_widget->rect().translated(m_widget->mapTo(m_widget->window(), QPoint()));
- }
-
+ QRectF boundingRect(Qt::CoordinateSystem system) const;
void draw(QPainter *p);
QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset) const;
diff --git a/src/gui/kernel/qwidget_qws.cpp b/src/gui/kernel/qwidget_qws.cpp
index ea3cef2bc..98d48def2 100644
--- a/src/gui/kernel/qwidget_qws.cpp
+++ b/src/gui/kernel/qwidget_qws.cpp
@@ -258,7 +258,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
Q_D(QWidget);
if (!isWindow() && parentWidget())
- parentWidget()->d_func()->invalidateBuffer(geometry());
+ parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
d->deactivateWidgetCleanup();
if (testAttribute(Qt::WA_WState_Created)) {
@@ -312,7 +312,7 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
Q_Q(QWidget);
bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
- q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
#ifndef QT_NO_CURSOR
QCursor oldcurs;
bool setcurs=q->testAttribute(Qt::WA_SetCursor);
@@ -805,7 +805,7 @@ void QWidgetPrivate::lower_sys()
QWSChangeAltitudeCommand::Lower);
} else if (QWidget *p = q->parentWidget()) {
setDirtyOpaqueRegion();
- p->d_func()->invalidateBuffer(q->geometry());
+ p->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
}
}
@@ -814,7 +814,7 @@ void QWidgetPrivate::stackUnder_sys(QWidget*)
Q_Q(QWidget);
if (QWidget *p = q->parentWidget()) {
setDirtyOpaqueRegion();
- p->d_func()->invalidateBuffer(q->geometry());
+ p->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
}
}
diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp
index 77ab590ed..5f7bb5a98 100644
--- a/src/gui/kernel/qwidget_win.cpp
+++ b/src/gui/kernel/qwidget_win.cpp
@@ -535,7 +535,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
{
Q_D(QWidget);
if (!isWindow() && parentWidget())
- parentWidget()->d_func()->invalidateBuffer(geometry());
+ parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
d->deactivateWidgetCleanup();
if (testAttribute(Qt::WA_WState_Created)) {
setAttribute(Qt::WA_WState_Created, false);
@@ -597,7 +597,7 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
Q_Q(QWidget);
bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
- q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
WId old_winid = data.winid;
// hide and reparent our own window away. Otherwise we might get
diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp
index de38b4c41..a4ee21be6 100644
--- a/src/gui/kernel/qwidget_x11.cpp
+++ b/src/gui/kernel/qwidget_x11.cpp
@@ -971,7 +971,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
{
Q_D(QWidget);
if (!isWindow() && parentWidget())
- parentWidget()->d_func()->invalidateBuffer(geometry());
+ parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
d->deactivateWidgetCleanup();
if (testAttribute(Qt::WA_WState_Created)) {
setAttribute(Qt::WA_WState_Created, false);
@@ -1050,7 +1050,7 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
QTLWExtra *topData = maybeTopData();
bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
- q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
extern void qPRCreate(const QWidget *, Window);
#ifndef QT_NO_CURSOR
QCursor oldcurs;
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index fdbdef01f..1c31e331f 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -559,7 +559,8 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
}
const QPoint offset = widget->mapTo(tlw, QPoint());
- if (qt_region_strictContains(dirty, widget->rect().translated(offset))) {
+ const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect());
+ if (qt_region_strictContains(dirty, widgetRect.translated(offset))) {
if (updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
return; // Already dirty.
@@ -567,7 +568,10 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
if (invalidateBuffer) {
const bool eventAlreadyPosted = !dirty.isEmpty();
- dirty += rgn.translated(offset);
+ if (widget->d_func()->graphicsEffect)
+ dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset);
+ else
+ dirty += rgn.translated(offset);
if (!eventAlreadyPosted || updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
return;
@@ -580,8 +584,12 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
}
if (widget->d_func()->inDirtyList) {
- if (!qt_region_strictContains(widget->d_func()->dirty, widget->rect()))
- widget->d_func()->dirty += rgn;
+ if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) {
+ if (widget->d_func()->graphicsEffect)
+ widget->d_func()->dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect());
+ else
+ widget->d_func()->dirty += rgn;
+ }
} else {
addDirtyWidget(widget, rgn);
}
@@ -625,7 +633,8 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd
return;
}
- const QRect translatedRect(rect.translated(widget->mapTo(tlw, QPoint())));
+ const QRect widgetRect = widget->d_func()->effectiveRectFor(rect);
+ const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint())));
if (qt_region_strictContains(dirty, translatedRect)) {
if (updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
@@ -647,8 +656,8 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd
}
if (widget->d_func()->inDirtyList) {
- if (!qt_region_strictContains(widget->d_func()->dirty, rect))
- widget->d_func()->dirty += rect;
+ if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect))
+ widget->d_func()->dirty += widgetRect;
} else {
addDirtyWidget(widget, rect);
}
@@ -880,7 +889,7 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
&& !isOverlapped(sourceRect) && !isOverlapped(destRect);
if (!accelerateMove) {
- QRegion parentR(parentRect);
+ QRegion parentR(effectiveRectFor(parentRect));
if (!extra || !extra->hasMask) {
parentR -= newRect;
} else {
@@ -1384,7 +1393,7 @@ void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const Q
const QRect newWidgetRect(q->rect());
const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height());
- if (!staticContents) {
+ if (!staticContents || graphicsEffect) {
QRegion staticChildren;
QWidgetBackingStore *bs = 0;
if (offset.isNull() && (bs = maybeBackingStore()))
@@ -1404,19 +1413,19 @@ void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const Q
return;
// Invalidate newly exposed area of the parent.
- if (extra && extra->hasMask) {
+ if (!graphicsEffect && extra && extra->hasMask) {
QRegion parentExpose(extra->mask.translated(oldPos));
parentExpose &= QRect(oldPos, oldSize);
if (hasStaticChildren)
parentExpose -= data.crect; // Offset is unchanged, safe to do this.
q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
} else {
- if (hasStaticChildren) {
+ if (hasStaticChildren && !graphicsEffect) {
QRegion parentExpose(QRect(oldPos, oldSize));
parentExpose -= data.crect; // Offset is unchanged, safe to do this.
q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
} else {
- q->parentWidget()->d_func()->invalidateBuffer(QRect(oldPos, oldSize));
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(QRect(oldPos, oldSize)));
}
}
return;
@@ -1474,7 +1483,7 @@ void QWidgetPrivate::invalidateBuffer(const QRegion &rgn)
QRegion wrgn(rgn);
wrgn &= clipRect();
- if (extra && extra->hasMask)
+ if (!graphicsEffect && extra && extra->hasMask)
wrgn &= extra->mask;
if (wrgn.isEmpty())
return;
@@ -1502,7 +1511,7 @@ void QWidgetPrivate::invalidateBuffer(const QRect &rect)
if (wRect.isEmpty())
return;
- if (!extra || !extra->hasMask) {
+ if (graphicsEffect || !extra || !extra->hasMask) {
tlwExtra->backingStore->markDirty(wRect, q, false, true);
return;
}
diff --git a/src/gui/painting/qbackingstore_p.h b/src/gui/painting/qbackingstore_p.h
index ddc0a5966..b21d504f7 100644
--- a/src/gui/painting/qbackingstore_p.h
+++ b/src/gui/painting/qbackingstore_p.h
@@ -144,9 +144,13 @@ private:
inline void addDirtyWidget(QWidget *widget, const QRegion &rgn)
{
if (widget && !widget->d_func()->inDirtyList && !widget->data->in_destructor) {
- widget->d_func()->dirty = rgn;
+ QWidgetPrivate *widgetPrivate = widget->d_func();
+ if (widgetPrivate->graphicsEffect)
+ widgetPrivate->dirty = widgetPrivate->effectiveRectFor(rgn.boundingRect());
+ else
+ widgetPrivate->dirty = rgn;
dirtyWidgets.append(widget);
- widget->d_func()->inDirtyList = true;
+ widgetPrivate->inDirtyList = true;
}
}